fcc09dc
@@ -102,7 +102,7 @@
public class Result implements CellScannable, CellScanner {
 
   private static ThreadLocal<byte[]> localBuffer = new ThreadLocal<byte[]>();
   private static final int PAD_WIDTH = 128;
-  public static final Result EMPTY_RESULT = new Result();
+  public static final Result EMPTY_RESULT = new Result(true);
 
   private final static int INITIAL_CELLSCANNER_INDEX = -1;
 
@@ -112,6 +112,8 @@
public class Result implements CellScannable, CellScanner {
   private int cellScannerIndex = INITIAL_CELLSCANNER_INDEX;
   private ClientProtos.RegionLoadStats stats;
 
+  private final boolean readonly;
+
   /**
    * Creates an empty Result w/ no KeyValue payload; returns null if you call {@link #rawCells()}.
    * Use this to represent no results if {@code null} won't do or in old 'mapred' as opposed
@@ -119,7 +121,16 @@
public class Result implements CellScannable, CellScanner {
    * {@link #copyFrom(Result)} call.
    */
   public Result() {
-    super();
+    this(false);
+  }
+
+  /**
+   * Allows to construct special purpose immutable Result objects,
+   * such as EMPTY_RESULT.
+   * @param readonly whether this Result instance is readonly
+   */
+  private Result(boolean readonly) {
+    this.readonly = readonly;
   }
 
   /**
@@ -172,6 +183,7 @@
public class Result implements CellScannable, CellScanner {
     this.exists = exists;
     this.stale = stale;
     this.partial = partial;
+    this.readonly = false;
   }
 
   /**
@@ -834,9 +846,12 @@
public class Result implements CellScannable, CellScanner {
 
   /**
    * Copy another Result into this one. Needed for the old Mapred framework
+   * @throws UnsupportedOperationException if invoked on instance of EMPTY_RESULT
+   * (which is supposed to be immutable).
    * @param other
    */
   public void copyFrom(Result other) {
+    checkReadonly();
     this.row = null;
     this.familyMap = null;
     this.cells = other.cells;
@@ -866,6 +881,7 @@
public class Result implements CellScannable, CellScanner {
   }
 
   public void setExists(Boolean exists) {
+    checkReadonly();
     this.exists = exists;
   }
 
@@ -891,8 +907,11 @@
public class Result implements CellScannable, CellScanner {
   /**
    * Add load information about the region to the information about the result
    * @param loadStats statistics about the current region from which this was returned
+   * @throws UnsupportedOperationException if invoked on instance of EMPTY_RESULT
+   * (which is supposed to be immutable).
    */
   public void addResults(ClientProtos.RegionLoadStats loadStats) {
+    checkReadonly();
     this.stats = loadStats;
   }
 
@@ -903,4 +922,14 @@
public class Result implements CellScannable, CellScanner {
   public ClientProtos.RegionLoadStats getStats() {
     return stats;
   }
+
+  /**
+   * All methods modifying state of Result object must call this method
+   * to ensure that special purpose immutable Results can't be accidentally modified.
+   */
+  private void checkReadonly() {
+    if (readonly == true) {
+      throw new UnsupportedOperationException("Attempting to modify readonly EMPTY_RESULT!");
+    }
+  }
 }
\ No newline at end of file
